package com.weikjie.stream.classes;

import com.weikjie.stream.interfaces.Consumer;
import com.weikjie.stream.interfaces.Function;
import com.weikjie.stream.interfaces.Predicate;

import java.util.*;

/**
 * @author weikjie
 * @description 仿jdk1.8流式操作
 * @since 2024/8/13 14:17
 */
public class Stream<T> {
    private final Collection<T> elements;

    /**
     * 构造方法
     *
     * @param elements 集合
     */
    private Stream(Collection<T> elements) {
        this.elements = elements == null ? new ArrayList<T>() : elements;
    }

    /**
     * 从集合创建流
     *
     * @param elements 元素集合
     * @param <T>      集合元素类型
     * @return 创建的流对象
     */
    public static <T> Stream<T> of(Collection<T> elements) {
        return new Stream<>(elements);
    }

    /**
     * 从数组创建流
     *
     * @param ts  元素数组
     * @param <T> 数组元素类型
     * @return 创建的流对象
     */
    @SafeVarargs
    public static <T> Stream<T> of(T... ts) {
        Collection<T> list = new ArrayList<>();
        for (T t : ts) {
            if (t != null) {
                list.add(t);
            }
        }
        return new Stream<>(list);
    }

    /**
     * 对流中的元素进行过滤
     *
     * @param predicate 过滤条件
     * @param <T>       流中元素类型
     * @return 过滤后的流对象
     */
    public Stream<T> filter(Predicate<T> predicate) {
        Collection<T> filtered = new ArrayList<>();
        for (T element : elements) {
            if (predicate.test(element)) {
                filtered.add(element);
            }
        }
        return new Stream<>(filtered);
    }

    /**
     * 对流中的每个元素执行映射操作
     *
     * @param mapper 映射函数
     * @param <R>    映射后的元素类型
     * @return 映射后的流对象
     */
    public <R> Stream<R> map(Function<T, R> mapper) {
        Collection<R> mapped = new ArrayList<>();
        for (T element : elements) {
            mapped.add(mapper.apply(element));
        }
        return new Stream<>(mapped);
    }

    /**
     * 将流转换为列表
     *
     * @return 转换后的列表
     */
    public List<T> toList() {
        return new ArrayList<>(elements);
    }

    /**
     * 将流转换为集合
     *
     * @return 转换后的集合
     */
    public Set<T> toSet() {
        return new HashSet<>(elements);
    }

    /**
     * 对流中的每个元素执行给定的消费操作
     *
     * @param consumer 消费操作
     * @param <T>      流中元素类型
     * @return 流对象本身，支持链式调用
     */
    public Stream<T> peek(Consumer<T> consumer) {
        for (T element : elements) {
            consumer.accept(element);
        }
        return this;
    }

    /**
     * 对流中的每个元素执行给定的消费操作
     *
     * @param consumer 消费操作
     * @param <T>      流中元素类型
     * @return 流对象本身，支持链式调用
     */
    public Stream<T> forEach(Consumer<T> consumer) {
        for (T element : elements) {
            consumer.accept(element);
        }
        return this;
    }

    /**
     * 对流中的每个元素执行扁平化映射操作
     *
     * @param mapper 映射函数，将每个元素映射到一个集合
     * @param <R>    映射后的元素类型
     * @return 扁平化后的流对象
     */
    public <R> Stream<R> flatMap(Function<T, Collection<R>> mapper) {
        Collection<R> flatMapped = new ArrayList<>();
        for (T element : elements) {
            flatMapped.addAll(mapper.apply(element));
        }
        return new Stream<>(flatMapped);
    }

    /**
     * 将流中的元素转换为映射
     *
     * @param keyMapper   键映射函数
     * @param valueMapper 值映射函数
     * @param <K>         映射键的类型
     * @param <V>         映射值的类型
     * @return 转换后的映射
     */
    public <K, V> Map<K, V> toMap(Function<T, K> keyMapper, Function<T, V> valueMapper) {
        Map<K, V> map = new HashMap<>();
        for (T element : elements) {
            map.put(keyMapper.apply(element), valueMapper.apply(element));
        }
        return map;
    }

    /**
     * 根据指定的分类函数将流中的元素分组
     *
     * @param classifier 分类函数
     * @param <K>        分组键的类型
     * @return 分组后的映射
     */
    public <K> Map<K, List<T>> groupBy(Function<T, K> classifier) {
        Map<K, List<T>> grouped = new HashMap<>();
        for (T element : elements) {
            K key = classifier.apply(element);
            List<T> group = grouped.get(key);
            if (group == null) {
                group = new ArrayList<>();
                grouped.put(key, group);
            }
            group.add(element);
        }
        return grouped;
    }

    /**
     * 遍历Map的键
     *
     * @param map         要遍历的Map
     * @param keyConsumer 对每个键执行的消费操作
     * @param <K>         Map键的类型
     * @param <V>         Map值的类型
     */
    public static <K, V> void forEachMapKey(Map<K, V> map, Consumer<K> keyConsumer) {
        for (K key : map.keySet()) {
            keyConsumer.accept(key);
        }
    }

    /**
     * 遍历Map的值
     *
     * @param map           要遍历的Map
     * @param valueConsumer 对每个值执行的消费操作
     * @param <K>           Map键的类型
     * @param <V>           Map值的类型
     */
    public static <K, V> void forEachMapValue(Map<K, V> map, Consumer<V> valueConsumer) {
        for (V value : map.values()) {
            valueConsumer.accept(value);
        }
    }

    /**
     * 遍历Map的条目
     *
     * @param map           要遍历的Map
     * @param entryConsumer 对每个条目执行的消费操作
     * @param <K>           Map键的类型
     * @param <V>           Map值的类型
     */
    public static <K, V> void forEachMap(Map<K, V> map, Consumer<Map.Entry<K, V>> entryConsumer) {
        for (Map.Entry<K, V> entry : map.entrySet()) {
            entryConsumer.accept(entry);
        }
    }

}
